package com.openspring.framework.util;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;

/**
 * 反射工具类
 * @author HeBin
 *
 */
public class GenericUtils {
	
	/**
	 * 通过反射,获得指定类的父类的泛型参数的实际类型
	 * @param clazz 需要反射的类,该类必须继承范型父类
	 * @param index 泛型参数所在索引,从0开始
	 * @return 范型参数的实际类型, 如果没有实现ParameterizedType接口, 即不支持泛型, 所以直接返回Object.class
	 */
	public static Class<?> getGenericSuperArgumentsclass(Class<?> clazz, int index) {
		Type superType = clazz.getGenericSuperclass();//得到泛型父类
		//如果没有实现ParameterizedType接口，即不支持泛型，直接返回Object.class
		if (!(superType instanceof ParameterizedType)) {
			return Object.class;
		}
		//返回表示此类型实际类型参数的Type对象的数组,数组里放的都是对应类型的Class
		Type[] generics = ((ParameterizedType) superType).getActualTypeArguments();
		if (!(generics[index] instanceof Class)) {
			return Object.class;
		}
		return (Class<?>) generics[index];
	}
	
	/**
	 * 通过反射,获得指定类的父类的第一个泛型参数的实际类型
	 * @param clazz 需要反射的类,该类必须继承泛型父类
	 * @return 泛型参数的实际类型, 如果没有实现ParameterizedType接口, 即不支持泛型, 所以直接返回Object.class
	 */
	public static Class<?> getGenericSuperArgumentsclass(Class<?> clazz) {
		return getGenericSuperArgumentsclass(clazz, 0);
	}

	/**
	 * 通过反射,获得方法返回值泛型参数的实际类型
	 * @param method 方法
	 * @param index 泛型参数所在索引,从0开始.
	 * @return 泛型参数的实际类型, 如果没有实现ParameterizedType接口，即不支持泛型，所以直接返回Object.class
	 */
	public static Class<?> getMethodGenericReturnType(Method method, int index) {
		Type returnType = method.getGenericReturnType();
		if (returnType instanceof ParameterizedType) {
			Type[] typeArguments = ((ParameterizedType) returnType).getActualTypeArguments();
			return (Class<?>) typeArguments[index];
		}
		return Object.class;
	}

	/**
	 * 通过反射,获得方法返回值第一个泛型参数的实际类型
	 * @param method 方法
	 * @return 泛型参数的实际类型, 如果没有实现ParameterizedType接口, 即不支持泛型, 所以直接返回Object.class
	 */
	public static Class<?> getMethodGenericReturnType(Method method) {
		return getMethodGenericReturnType(method, 0);
	}

	/**
	 * 通过反射,获得方法输入参数第index个输入参数的所有泛型参数的实际类型
	 * @param method 方法
	 * @param index 第几个输入参数
	 * @return 输入参数的泛型参数的实际类型集合, 如果没有实现ParameterizedType接口, 即不支持泛型, 所以直接返回空集合
	 */
	public static List<Class<?>> getMethodGenericParameterTypes(Method method, int index) {
		List<Class<?>> results = new ArrayList<Class<?>>();
		Type[] genericParameterTypes = method.getGenericParameterTypes();
		Type genericParameterType = genericParameterTypes[index];
		if (genericParameterType instanceof ParameterizedType) {
			Type[] parameterArgTypes = ((ParameterizedType) genericParameterType).getActualTypeArguments();
			for (Type parameterArgType : parameterArgTypes) {
				Class<?> parameterArgClass = (Class<?>) parameterArgType;
				results.add(parameterArgClass);
			}
			return results;
		}
		return results;
	}

	/**
	 * 通过反射,获得方法输入参数第一个输入参数的所有泛型参数的实际类型
	 * @param method 方法
	 * @return 输入参数的泛型参数的实际类型集合, 如果没有实现ParameterizedType接口, 即不支持泛型, 所以直接返回空集合
	 */
	public static List<Class<?>> getMethodGenericParameterTypes(Method method) {
		return getMethodGenericParameterTypes(method, 0);
	}

	/**
	 * 通过反射,获得Field泛型参数的实际类型
	 * @param field 字段
	 * @param index 泛型参数所在索引,从0开始.
	 * @return 泛型参数的实际类型, 如果没有实现ParameterizedType接口, 即不支持泛型, 所以直接返回Object.class
	 */
	public static Class<?> getFieldGenericType(Field field, int index) {
		Type genericFieldType = field.getGenericType();
		if (genericFieldType instanceof ParameterizedType) {
			Type[] fieldArgTypes = ((ParameterizedType) genericFieldType).getActualTypeArguments();
			return (Class<?>) fieldArgTypes[index];
		}
		return Object.class;
	}

	/**
	 * 通过反射,获得Field泛型参数的实际类型
	 * @param field 字段
	 * @return 泛型参数的实际类型, 如果没有实现ParameterizedType接口, 即不支持泛型, 所以直接返回Object.class
	 */
	public static Class<?> getFieldGenericType(Field field) {
		return getFieldGenericType(field, 0);
	}
}
